import 'dart:io';

import 'package:bot_toast/bot_toast.dart';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:github_client_app/env/env.dart';
import 'package:github_client_app/services/http/dio_interceptors.dart';
import 'package:provider/provider.dart';

// 请求方法
enum DioMethod { get, post, put, delete, patch, head }

/// 使用拓展枚举替代 switch判断取值
/// https://zhuanlan.zhihu.com/p/98545689
extension MethodExtension on DioMethod {
  String get value => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'][index];
}

class DioUtil {
  // 连接超时时间
  static const Duration _connectTime = Duration(seconds: 60);
  // 响应超时时间
  static const Duration _receiveTime = Duration(seconds: 60);
  // 请求url前缀
  static final String _baseUrl = Env.envConfig.envHttpUrl;

  // 单例模式
  static DioUtil? _instance;
  factory DioUtil() => _instance ?? DioUtil._internal();

  late Dio _dio;
  Dio get dio => _dio;

  DioUtil._internal() {
    // print('object');
    _instance = this;
    _instance!._init();
  }

  _init() {
    // 初始化基本选项
    BaseOptions options = BaseOptions(
      baseUrl: _baseUrl,
      connectTimeout: _connectTime,
      receiveTimeout: _receiveTime,
    );

    // 初始化dio
    _dio = Dio(options)
      // 配置http2证书
      ..httpClientAdapter = Http2Adapter(
        ConnectionManager(
          idleTimeout: const Duration(seconds: 10),
          onClientCreate: (_, config) =>
              config.onBadCertificate = (X509Certificate cert) {
            // print(cert);
            return true;
          },
        ),
      );
    ;

    // dio请求执行流程：请求拦截器--请求转换器--发起请求--响应转换器--响应拦截器--最终结果
    // 添加拦截
    _dio.interceptors.add(DioInterceptors());

    // ignore: deprecated_member_use
    // (dio.httpClientAdapter as IOHttpClientAdapter).onHttpClientCreate =
    //     (client) {
    //   client.badCertificateCallback = (cert, host, port) {
    //     return true;
    //   };
    //   return null;
    // };
  }

  /// 取消请求token
  final CancelToken _cancelToken = CancelToken();

  // 发送请求方法
  Future<T> request<T>(String path,
      {DioMethod method = DioMethod.get,
      Map<String, dynamic>? params,
      data,
      CancelToken? cancelToken,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress,
      bool loading = false}) async {
    // print(options);

    // 将请求方法组合到options中
    options ??= Options();
    options.method = method.value;
    // print(options);

    dynamic cancel;
    if (loading) {
      // 自定义loading
      cancel = BotToast.showCustomLoading(
        toastBuilder: (cancelFunc) => Container(
          color: Colors.white,
          height: 50,
          width: 60,
          child: const Text('dddd'),
        ),
      );
    }

    try {
      // 调用dio的请求方法
      Response response;
      response = await _dio.request(path,
          data: data,
          queryParameters: params,
          cancelToken: cancelToken ?? _cancelToken,
          options: options,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress);
      // // print(response);
      if (loading && cancel != null) {
        cancel();
      }
      return response.data;
    } on DioException catch (_) {
      if (loading && cancel != null) {
        cancel();
      }
      rethrow;
    }
  }

  // 取消请求方法
  void cancelRequests() {
    _cancelToken.cancel("cancel");
  }

  // get请求
  Future<T> get<T>(
          {required String url,
          Map<String, dynamic>? params,
          CancelToken? cancelToken,
          Options? options,
          ProgressCallback? onSendProgress,
          ProgressCallback? onReceiveProgress,
          bool loading = false}) =>
      request(url,
          method: DioMethod.get,
          params: params,
          cancelToken: cancelToken,
          options: options,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
          loading: loading);

  // POST 请求
  Future<T> post<T>(
          {required String url,
          Object? data,
          CancelToken? cancelToken,
          Options? options,
          ProgressCallback? onSendProgress,
          ProgressCallback? onReceiveProgress,
          bool loading = false}) =>
      request(url,
          method: DioMethod.post,
          data: data,
          cancelToken: cancelToken,
          options: options,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
          loading: false);
}
